1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Functions and data types for setting parameter values.
//!
//! # Functions
//!
//! * [`set_parameter_float`](VoicemeeterRemote::set_parameter_float)
//! * [`set_parameter_string`](VoicemeeterRemote::set_parameter_string)
//! * [`set_parameters`](VoicemeeterRemote::set_parameters)
use std::ffi::CString;

use crate::types::ParameterNameRef;

use crate::VoicemeeterRemote;

impl VoicemeeterRemote {
    /// Set the float value of a parameter. See also [`VoicemeeterRemote::parameters()`] to do this with functions.
    #[tracing::instrument(skip(self))]
    pub fn set_parameter_float(
        &self,
        param: &ParameterNameRef,
        value: f32,
    ) -> Result<(), SetParameterError> {
        let param = CString::new(param.as_ref()).unwrap();
        tracing::debug!("setting float parameter");
        let res = unsafe {
            self.raw
                .VBVMR_SetParameterFloat(param.as_ptr() as *mut _, value)
        };
        match res {
            0 => Ok(()),
            -1 => Err(SetParameterError::CannotGetClient),
            -2 => Err(SetParameterError::NoServer),
            -3 => Err(SetParameterError::UnknownParameter(
                param.to_string_lossy().into_owned(),
            )), // NOTE: Lossless always (assuming vmr doesn't modify :) ), unsafe?
            s => Err(SetParameterError::Other(s)),
        }
    }

    /// Set the string value of a parameter. See also [`VoicemeeterRemote::parameters()`] to do this with functions.
    #[tracing::instrument(skip(self))]
    pub fn set_parameter_string(
        &self,
        param: &ParameterNameRef,
        value: &str,
    ) -> Result<(), SetParameterError> {
        let param = CString::new(param.as_ref()).unwrap();
        let value = CString::new(value).unwrap();
        tracing::debug!("setting string parameter");
        let res = unsafe {
            self.raw
                .VBVMR_SetParameterStringA(param.as_ptr() as *mut _, value.as_ptr() as *mut _)
        };
        match res {
            0 => Ok(()),
            -1 => Err(SetParameterError::CannotGetClient),
            -2 => Err(SetParameterError::NoServer),
            -3 => Err(SetParameterError::UnknownParameter(
                param.to_string_lossy().into_owned(),
            )), // NOTE: Lossless always (assuming vmr doesn't modify :) ), unsafe?
            s => Err(SetParameterError::Other(s)),
        }
    }

    // TODO: Example script.
    /// Set parameters using a script. Similar to macro button scripts.
    pub fn set_parameters(&self, script: &str) -> Result<(), SetParametersError> {
        let script = CString::new(script).unwrap();
        let res = unsafe { self.raw.VBVMR_SetParameters(script.as_ptr() as *mut _) };

        match res {
            l if l > 0 => Err(SetParametersError::ScriptError(l as usize)),
            0 => Ok(()),
            -1 => Err(SetParameterError::CannotGetClient.into()),
            -2 => Err(SetParameterError::NoServer.into()),
            s => Err(SetParameterError::Other(s).into()),
        }
    }
}

/// Errors that can happen when setting parameters.
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum SetParametersError {
    /// Script error
    #[error("script error on line: {0}")]
    ScriptError(usize),
    /// An error occured when setting parameters.
    #[error(transparent)]
    SetParameterError(#[from] SetParameterError),
}

/// Errors that can happen when setting a parameter.
#[derive(Debug, thiserror::Error, Clone)]
#[non_exhaustive]
pub enum SetParameterError {
    // TODO: is this correct? docs say "error (unexpected)""
    /// Cannot get client.
    #[error("cannot get client (unexpected)")]
    CannotGetClient,
    /// No server.
    #[error("no server")]
    NoServer,
    /// Unknown parameter.
    #[error("unknown parameter: {0}")]
    UnknownParameter(String),
    /// An unknown error code occured.
    #[error("unexpected error occurred: error code {0}")]
    Other(i32),
}